/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package gui;

import java.awt.Container;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFileChooser;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.matchers.VarMatcher;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.variable.types.ArrayType;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.SetProperty.Flag;
import tal.drivechain.variable.VarTableAction;
import tal.drivechain.variable.VarTableAction.Action;
import tal.drivechain.variable.Variable;

/**
 *
 * @author eisental
 */
public class FileChooser extends Module {
    protected JFileChooser chooser;
    protected Container parent;
    protected VarMatcher showTrigger;
    protected String actionLabel;
    protected final Variable RESULT_CANCEL = new Variable("cancel", DataType.EVENT, null);
    protected final Variable RESULT_ERROR = new Variable("error", DataType.EVENT, null);
    protected Variable selection;
    protected VarTableAction setSelection;
    protected Variable onApprove;
    private String parentId;
    private Variable currentDirectory;

    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        chooser = new JFileChooser();
        setParent(props.getProperty("parent"), null);
        setDirectory(props.getProperty("directory"), null);
        setSelectedFile(props.getProperty("selectedFile"), null);
        setMultiSelection(props.getProperty("multiSelection"), null);
        setSelectionMode(props.getProperty("selectionMode"), null);
        setShowTrigger(props.getProperty("showTrigger"), null);
        setActionLabel(props.getProperty("actionLabel"), null);
        setOnApprove(props.getProperty("onApprove"), null);
        setSelection = new VarTableAction("selection", Action.SET_ANY);
    }

    public void setParent(Object value, Flag flag) {
        parentId = (String)value;
        if (this.isRunning()) {
            this.stop();
            this.start();
        }
    } public Object getParent() { return parentId; }

    public void setDirectory(Object value, Flag flag) {
        currentDirectory = (Variable)value;
        String sfile = (String)currentDirectory.getValue(this);
        chooser.setCurrentDirectory(new File(sfile));
        if (infoFlag)
            log("Current directory: " + chooser.getCurrentDirectory(), MSG.INFO);
    } public Object getDirectory() { return currentDirectory; }

    public void setMultiSelection(Object value, Flag flag) {
        boolean multisel = (Boolean)value;
        chooser.setMultiSelectionEnabled(multisel);
        if (multisel)
            selection = new Variable("selection", new ArrayType(DataType.STRING), new ArrayList<String>(), true);
        else selection = new Variable("selection", DataType.STRING, null, true);
    } public Object getMultiSelection() { return chooser.isMultiSelectionEnabled(); }

    public void setSelectionMode(Object value, Flag flag) {
        chooser.setFileSelectionMode(parseSelectionMode((String)value));
    } public Object getSelectionMode() { return modeToString(chooser.getFileSelectionMode()); }

    public void setSelectedFile(Object value, Flag flag) {
        List<Object> objFiles = (List<Object>)value;
        if (objFiles.size()>1 && chooser.isMultiSelectionEnabled()) {
            List<File> selectedFiles = new ArrayList<File>();
            if (flag==Flag.ADD) {
                selectedFiles.addAll(Arrays.asList(chooser.getSelectedFiles()));
            }

            for (Object obj : objFiles)
                selectedFiles.add((File)obj);

            chooser.setSelectedFiles(selectedFiles.toArray(new File[]{}));

        } else if (objFiles.size()>0) {
            log("Can't select more than one file when multiSelection is off.", MSG.WARNING);
            chooser.setSelectedFile((File)objFiles.get(0));
        }
    } public Object getSelectedFile() {
        try {
            List ret = new ArrayList();
            for (File f : chooser.getSelectedFiles()) {
                ret.add(f.getCanonicalPath());
            }
            return ret;
        } catch (IOException ex) {
            throw new IllegalArgumentException(ex.getMessage());
        }
    }

    public void setShowTrigger(Object value, Flag flag) {
        showTrigger = (VarMatcher)value;
    } public Object getShowTrigger() { return showTrigger; }

    public void setOnApprove(Object value, Flag flag) {
        onApprove = (Variable)value;
    } public Object getOnApprove() { return onApprove; }

    public void setActionLabel(Object value, Flag flag) {
        actionLabel = (String)value;
    } public Object getActionLabel() { return actionLabel; }

    @Override
    public void start() {
        super.start();
        parent = (Container)getParentChain().findSharedObject(parentId);
        if (parent==null) {
            throw new IllegalArgumentException("A container with id " + parentId + " does not exist");
        }
    }

    private String modeToString(int fileSelectionMode) {
        switch (fileSelectionMode) {
            case JFileChooser.FILES_ONLY:
                return "files.only";
            case JFileChooser.FILES_AND_DIRECTORIES:
                return "files.and.directories";
            case JFileChooser.DIRECTORIES_ONLY:
                return "directories.only";
            default:
                throw new IllegalArgumentException("Unknown selectionMode code: " + fileSelectionMode);
        }
    }

    private int parseSelectionMode(String string) {
        string = string.trim();
        if (string.equals("files.only"))
            return JFileChooser.FILES_ONLY;
        else if (string.equals("files.and.directories"))
            return JFileChooser.FILES_AND_DIRECTORIES;
        else if (string.equals("directories.only"))
            return JFileChooser.DIRECTORIES_ONLY;
        else throw new IllegalArgumentException("Unknown selectionMode value: " + string);
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
        if (showTrigger.matches(in, channel, this)) {
            int result = chooser.showDialog(parent, actionLabel);
            if (result==JFileChooser.APPROVE_OPTION) {
                if (chooser.isMultiSelectionEnabled()) {
                    File[] selected = chooser.getSelectedFiles();
                    List list = (List)selection.getInternalValue();
                    list.clear();
                    try {
                        for (File f : selected)
                            list.add(f.getCanonicalPath());
                    } catch (IOException io) {
                        log("While processing filename: " + io, MSG.WARNING);
                    }
                    setSelection.set(selection, localVars, this);
                } else {
                    try {
                        selection.setValue(chooser.getSelectedFile().getCanonicalPath(), true);
                        setSelection.set(selection, localVars, this);
                    } catch (IOException ex) {
                        log("While processing filename: " + ex, MSG.WARNING);
                    }
                }
                sendToOutputs(onApprove, -1);
            } else if (result==JFileChooser.ERROR_OPTION)
                sendToOutputs(RESULT_ERROR, -1);
            else if (result==JFileChooser.CANCEL_OPTION)
                sendToOutputs(RESULT_CANCEL, -1);

        }
    }
}
